package trolling;

import org.apache.torque.NoRowsException;
import org.apache.torque.TooManyRowsException;
import org.apache.torque.Torque;
import org.apache.torque.TorqueException;
import org.apache.torque.util.Criteria;
import java.util.*;
import trolling.IO;
import torque.generated.*;

/**
 * Le Moteur est une extention du {@link Menu}, avec des fonctions bouclées permettant le déroulement du jeu. Mais comme on est plus dans les menus (Meme si ca y ressemble, vu que tout se ressemble en console Linux), on a préféré faire une nouvelle Classe.
 *
 */
public class Moteur {

	public final static String TORQUE_PROPS = new String(
			"torque-3.3//Torque.properties");
	/**
	 * Booleen exprimant le fait que la mapcache est a jour.
	 * <br>true si la carte est dans Mapcache
	 * <br>false si la carte doit etre rechargée par requettes sql
	 */
	private boolean Mapcacheup = false;
	/**
	 * Cache de la Map, permettant un affichage instantané quand il est a jour.
	 */
	private String Mapcache = "";

	/**
	 * Partie liée au {@link Moteur}. Le Moteur permet ainsi le fonctionnement de la {@link Partie} partie.
	 */
	Partie partie;

	/** Creer un {@link Moteur} de jeu pour la {@link Partie} partie.
	 * @param partie {@link Partie} concernée par le {@link Moteur}.
	 */
	public Moteur(Partie partie) {
		this.partie = partie;
		this.afficher();
		int etat = 0;
		while (partie.getTrollVivants().size() > 1) {
			do {
				etat = step();
			} while (etat == 1);
			if (etat == 0) {
				partie.nouveauTour();
			} else {
				return;
			}
		}

		System.out.println(":)" + partie.getTrollVivants().get(0).getNomtroll()
				+ " a gagné !");
		try {
			System.out.println(" Il a maintenant "+ partie.getTrollVivants().get(0).getTroll().getXp() + "XP !");
		} catch (TorqueException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		try {
			this.partie.delete();
		} catch (TorqueException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Affiche la carte.
	 * Cette fonction pourrait etre optimisée par une mise en cache constante des objets {@link Trolldanspartie}, {@link Objetdanspartie} et {@link Objetdanstrolldanspartie}.
	 */
	public void afficher() {
		IO.clear();
		if (Mapcacheup == true) {
			System.out.print(Mapcache);
			return;
		}
		String mc = ""; // map cache

		try {
			List<Trolldanspartie> trolls = partie.getTrollVivants();
			System.out.println("Chargement de la carte");
			mc += "\n+";

			for (int x = 0; x < partie.getLargeur(); x++) {
				mc += x;
				if(x<10) mc+="-";
			}
			mc += "-+\n";
			for (int x = 0; x < partie.getLargeur(); x++) {
				mc += x+"";
				if(x<10) mc+="|";
				for (int y = 0; y < partie.getLargeur(); y++) {
					List<Trolldanspartie> t = TrolldanspartiePeer.getTrolls(y,
							x, partie.getIdpartie());
					if (!t.isEmpty()) {
						mc += ":)";
					} else {
						if (partie.getObjet(y, x) != null) {

							mc += "[]";
						} else
							mc += "  ";
					}
					// System.out.print();
					t = null;
				}
				mc += "!\n";
			}
			mc += "+";
			for (int x = 0; x < partie.getLargeur(); x++) {
				mc += "--";
			}
			mc += "-+\n";
			Mapcache = mc;
			Mapcacheup = true;
			System.out.println(Mapcache);
		} catch (Exception e) {
			System.out.println("Erreur lors de l'affichage de la partie !");
			System.out.println(e.getMessage());
			e.printStackTrace();
		}
	}

	/** Etape du tour durant lequel un Troll joue. Il y a un Step pour chaque {@link Trolldanspartie} dans la {@link Partie}.
	 * @return <ul><li>0 : Si le Moteur doit effectuer un NouveauTour (Plus de {@link Trolldanspartie} avec un ordre>0)</li>
	 * <li>1 : Si Si tout s'est bien passé</li>
	 * <li>2 : Si l'utilisateur souhaite reprendre sa partie plus tard. Parce que certaines personnes préfèrent dormir.</li></ul>
	 */
	public int step() {
		try {
			Trolldanspartie trollc = partie.StepTrolls();
			int choix = 0;
			if (trollc == null)
				return 0;
			else {
				do {
					Objetdanspartie obj = partie.getObjet(trollc.getX(),
							trollc.getY());
					List<Trolldanspartie> ts = TrolldanspartiePeer.getTrolls(
							trollc.getX(), trollc.getY(), partie.getIdpartie());
					ts.remove(trollc);

					System.out.println("(" + trollc.getX() + ","
							+ trollc.getY() + ") : ");
					if (obj != null) {
						System.out.println("Il y a un(e) "+obj.getObjet().getType()+" : ["
								+ obj.getNomobjet() + "]");
						System.out.println("\""
								+ obj.getObjet().getDescription() + "\"");
						Objet o = obj.getObjet();
						if (o.getBonusattaque() != 0) {
							System.out.print(o.getBonusattaque() + "BA ");
						}
						if (o.getBonusdegat() != 0) {
							System.out.print(o.getBonusdegat() + "BD ");
						}
						if (o.getBonusesquive() != 0) {
							System.out.print(o.getBonusesquive() + "BE ");
						}
						if (o.getBonusvie() != 0) {
							System.out.print(o.getBonusvie() + "BV ");
						}
						System.out.println("");

					}
					if (!ts.isEmpty()) {
						System.out.println("Il y a " + ts.size()
								+ " Trolls !!!");
						for (Trolldanspartie t : ts) {
							System.out.println(":) " + t.getNomtroll() + " "
									+ t.getPv() + "PV");

							System.out.println(t.getTroll().getAttaque() + "A "
									+ t.getTroll().getDegat() + "D "
									+ t.getTroll().getEsquive() + "E");

							System.out.println("");
						}
					}
					if (obj == null && ts.isEmpty()) {
						System.out.println("La case est vide");
					}
					System.out.println("## :) " + trollc.getNomtroll() + "  " + trollc.getPa() + "PA " + trollc.getPv() + "PV1" +
							"");
					System.out.println("## ");
					System.out.println("## 1 - Se déplacer");
					System.out.println("## 2 - Voir la carte");
					if (obj != null)
						System.out.println("## 3 - Ramasser ["
								+ obj.getNomobjet() + "]");
					if (!ts.isEmpty())
						System.out.println("## 4 - Attaquer un Troll");
					if(trollc.getObjetdanstrolldansparties().size() > 0)
						System.out.println("## 5 - Inventaire ("+trollc.getObjetdanstrolldansparties().size()+" objets)");
					System.out.println("## 9 - Passer son tour");
					System.out
							.println("## 0 - Passer son tour, sauvegarder et quitter");
					System.out.print("Choix :");
					choix = IO.lireEntier();
					if (choix == 2) {
						this.afficher();
					}
					if (choix == 1) {
						this.seDeplacer(trollc);
					}
					if (choix==5){
						this.inventaire(trollc);
					}
					if (choix == 3 && obj != null) {
						trollc.ramasser();
					}
					if(choix==4 && !ts.isEmpty()){
						this.attaquer(trollc);
					}
				} while (trollc.getPa() != 0 && choix != 0 && choix != 9);
				if (trollc.getPa() == 0) {
					System.out.println("## 1 - Finir son tour");
					System.out.println("## 0 - Sauvegarder et quitter");
					System.out.print("Choix :");
					choix = IO.lireEntier();
					if (choix == 1)
						return 1;
				}

				if (choix == 0)
					return 2;
				else
					return 1;
			}
		} catch (TorqueException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return 0;
	}

	/** Permet a proposer a un {@link Trolldanspartie} troll de se deplacer sur les cartes voisines aux siennes qui ne sont pas en dehors des limites du terrain.
	 * @param troll {@link Trolldanspartie} revant de voyages.
	 */
	private void seDeplacer(Trolldanspartie troll) {
		this.afficher();
		int x, y, choix;
		x = troll.getX();
		y = troll.getY();
		System.out.println("Se déplacer en : ");
		if ((x + 1) < partie.getLargeur())
			System.out.println("	1 - -> (" + (x + 1) + "," + y + ")");
		if ((x - 1) > 0)
			System.out.println("	2 - <- (" + (x - 1) + "," + y + ")");
		if ((y + 1) < partie.getLargeur())
			System.out.println("	3 - \\/ (" + (x) + "," + (y + 1) + ")");
		if ((x - 1) > 0)
			System.out.println("	4 - /\\ (" + (x) + "," + (y - 1) + ")");
		System.out.println("	0 - Annuler");
		System.out.print("Choix : ");
		choix = IO.lireEntier();
		switch (choix) {
		case 1:
			if ((x + 1) < partie.getLargeur())
			this.Mapcacheup=!troll.seDeplacer(1, 0);
			break;
		case 2:
			if ((x - 1) > 0)
			this.Mapcacheup=!troll.seDeplacer(-1, 0);
			break;
		case 3:
			if ((y + 1) < partie.getLargeur())
			this.Mapcacheup=!troll.seDeplacer(0, 1);
			break;
		case 4:
			if ((y - 1) > 0)
			this.Mapcacheup=!troll.seDeplacer(0, -1);
			break;
		}

	}
	
	/** Fonction affichant l'inventaire du {@link Trolldanspartie} t pour qu'il s'équipe d'un des objets
	 * @param t {@link Trolldanspartie} dont on veut voir l'inventaire. Souvent le Troll dont il est le tour de jouer.
	 */
	private void inventaire(Trolldanspartie t){
		try {
			int choix;
			IO.clear();
			System.out.println("Inventaire de :) "+t.getNomtroll()+" :");
			List<Objetdanstrolldanspartie> objs = t.getObjetdanstrolldansparties();
			for(Objetdanstrolldanspartie obj : objs){
				System.out.print(objs.indexOf(obj));
				Objetdanspartie o = ObjetdanspartiePeer.retrieveByPK(t.getIdpartie(),obj.getXdepart(),obj.getYdepart());
				System.out.print(" - ["+o.getNomobjet());
				System.out.print("] - "+ o.getObjet().getType());
				if(obj.getEquipe())
					System.out.print(" (Equipé) ");
				System.out.println();
			}
			do{
			System.out.print("Choix : ");
			choix=IO.lireEntier();
			}while(0>choix || objs.size()<=choix);
			t.equiper(objs.get(choix));
		} catch (TorqueException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/** Propose a l'utilisateur de choisir un {@link Trolldanspartie} a attaquer
	 * @param trollc Troll courant
	 */
	private void attaquer(Trolldanspartie trollc){
		List<Trolldanspartie> ts = TrolldanspartiePeer.getTrolls(
				trollc.getX(), trollc.getY(), partie.getIdpartie());
		int choix;
		ts.remove(trollc);
		IO.clear();
		System.out.println("Choisissez un Troll a attaquer : ");
		for(Trolldanspartie t : ts){
			System.out.println("	" + ts.indexOf(t) +" - :) "+t.getNomtroll()+" ("+t.getPv()+"PV)");
		}
		do{
			choix=IO.lireEntier();
		}while(0>choix || ts.size()<=choix);
		Trolldanspartie trolla=ts.get(choix);
		this.Mapcacheup=!trollc.Attaquer(trolla);
	}
	
}
